package io.github.wslxm.springbootplus2.manage.sys.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.github.wslxm.springbootplus2.core.base.model.BasePage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.github.wslxm.springbootplus2.core.result.ResultType;
import io.github.wslxm.springbootplus2.utils.JwtUtil;
import io.github.wslxm.springbootplus2.core.base.service.impl.BaseServiceImpl;
import io.github.wslxm.springbootplus2.core.config.error.ErrorException;
import io.github.wslxm.springbootplus2.core.utils.XjBeanUtil;
import io.github.wslxm.springbootplus2.manage.sys.mapper.SysRoleMapper;
import io.github.wslxm.springbootplus2.manage.sys.model.dto.SysRoleDTO;
import io.github.wslxm.springbootplus2.manage.sys.model.entity.SysRole;
import io.github.wslxm.springbootplus2.manage.sys.model.entity.SysRoleUser;
import io.github.wslxm.springbootplus2.manage.sys.model.query.SysRoleQuery;
import io.github.wslxm.springbootplus2.manage.sys.model.vo.SysRoleVO;
import io.github.wslxm.springbootplus2.manage.sys.service.SysRoleMenuService;
import io.github.wslxm.springbootplus2.manage.sys.service.SysRoleService;
import io.github.wslxm.springbootplus2.manage.sys.service.SysRoleUserService;
import io.github.wslxm.springbootplus2.starter.redis.lock.XjDistributedLock;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author wangsong
 */
@Service
public class SysRoleServiceImpl extends BaseServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {

    /**
     * 超级管理员角色 code（勿修改）
     */
    private final static String ROLE_SYS = "SYS";
    @Autowired
    private SysRoleUserService roleUserService;
    @Autowired
    private SysRoleMenuService roleMenuService;


    @Override
    public BasePage<SysRoleVO> findPage(SysRoleQuery query) {

        // 是否只查询当前登录人创建的角色
        String loginUserId = ObjectUtil.defaultIfNull(query.getIsLoginUser(), () -> JwtUtil.getJwtUser(request).getUserId(), null);
        Boolean isUserIdChecked = ObjectUtil.defaultIfNull(query.getIsUserIdChecked(), false);
        String userId = query.getUserId();

        // 是否查询所有数据, 使用 isChecked 标记，将 queryUserId 单独存放起来
        if (isUserIdChecked) {
            query.setUserId(null);
        }
        // 查询
        Page<SysRoleVO> page = new Page<>(query.getCurrent(), query.getSize());
        page = page.setRecords(baseMapper.list(page, query, loginUserId));
        if (page.getRecords() == null || page.getRecords().size() == 0) {
            return XjBeanUtil.pageVo(page);
        }

        // 处理指定用户当前拥有的角色, isChecked 标记用户是否存在当前角色
        if (isUserIdChecked && StringUtils.isNotBlank(userId)) {
            List<SysRoleUser> roleUsers = roleUserService.list(new LambdaQueryWrapper<SysRoleUser>().eq(SysRoleUser::getUserId, userId));
            if (roleUsers != null && roleUsers.size() > 0) {
                List<String> userRoleIds = roleUsers.stream().map(SysRoleUser::getRoleId).collect(Collectors.toList());
                page.getRecords().forEach((p) -> p.setIsChecked(userRoleIds.contains(p.getId())));
            }
        }
        return XjBeanUtil.pageVo(page);
    }


    /**
     * 添加角色-默认有所有URL 权限
     *
     * @param dto
     * @return java.lang.Boolean
     * @author wangsong
     * @date 2020/9/19 0019 10:56
     * @version 1.0.1
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @XjDistributedLock(lockName = "'xj-sys-role_'+#dto.code", waitTime = 5L)
    public String insert(SysRoleDTO dto) {
        this.isCodeRepeat(dto.getCode(), null);

        SysRole role = dto.convert(SysRole.class);
        this.save(role);
        // 给角色分配菜单权限
        roleMenuService.updRoleMenus(role.getId(), dto.getMenuIds());
        return role.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @XjDistributedLock(lockName = "'xj-sys-role_'+#dto.code", waitTime = 5L)
    public Boolean upd(String id, SysRoleDTO dto) {
        this.isCodeRepeat(dto.getCode(), id);

        SysRole role = dto.convert(SysRole.class);
        role.setId(id);
        boolean b = this.updateById(role);

        // 编辑入口必传菜单，如果没传可能是在操作启用禁用等操作,不对菜单做处理
        if (dto.getMenuIds() != null && dto.getMenuIds().size() > 0) {
            // 给角色分配菜单权限(先删除后添加)
            roleMenuService.updRoleMenus(role.getId(), dto.getMenuIds());
        }
        return b;
    }


    @Override
    public SysRole findSysRole() {
        return this.getOne(new LambdaQueryWrapper<SysRole>().eq(SysRole::getCode, ROLE_SYS));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean del(String roleId) {
        // 删除角色和角色相关的关系表
        roleUserService.delByRoleId(roleId);
        roleMenuService.delByRoleId(roleId);
        return this.removeById(roleId);
    }


    /**
     * 角色code重复验证
     *
     * @author wangsong
     * @mail 1720696548@qq.com
     * @date 2022/8/20 0020 14:33
     * @version 1.0.0
     */
    private void isCodeRepeat(String code, String excludeId) {
        long count = this.count(new LambdaQueryWrapper<SysRole>()
                .eq(SysRole::getCode, code)
                .ne(SysRole::getId, excludeId)
        );
        if (count > 0) {
            throw new ErrorException(ResultType.BASE_CODE_REPEAT);
        }
    }
}